<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<!--  -*- coding: utf-8 -*- -->
    <head>
<!--
###############################################################################
# Copyright (c) 2011, Vadim Shlyakhov
#
#  Permission is hereby granted, free of charge, to any person obtaining a
#  copy of this software and associated documentation files (the "Software"),
#  to deal in the Software without restriction, including without limitation
#  the rights to use, copy, modify, merge, publish, distribute, sublicense,
#  and/or sell copies of the Software, and to permit persons to whom the
#  Software is furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included
#  in all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
#  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
#  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#  DEALINGS IN THE SOFTWARE.
###############################################################################
-->
        <title>tiles-openlayers</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

        <!--
        <script src='http://openlayers.org/api/2.11-rc2/OpenLayers.js'></script>
        <script src='http://maps.google.com/maps?file=api&amp;v=2'></script>
        <script src='http://proj4js.org/lib/proj4js-combined.js'></script>
        <script src='http://proj4js.org/lib/proj4js-compressed.js'></script>
        <script src='http://openlayers.org/api/OpenLayers.js'></script>
        <script src='http://dev.openlayers.org/releases/OpenLayers-2.12/OpenLayers.debug.js'></script>
        <script src='http://dev.openlayers.org/releases/OpenLayers-2.12/OpenLayers.js'></script>
        -->

        <script src="http://maps.google.com/maps/api/js?v=3&amp;sensor=false"></script>
        <script src='http://cdnjs.cloudflare.com/ajax/libs/openlayers/2.13.1/OpenLayers.js'></script>
        <style>
            .olLayerGooglePoweredBy, .olLayerGoogleCopyright{visibility: hidden;right:3px;bottom:2px;left:auto;}
/*
*/
            .olImageLoadError {
                opacity: 0 !important;
                filter: alpha(opacity=0) !important;
            }
            html,body {
                height: 99%;
                width: 99%;
            }
            #map {
                width: 100%;
                height: 100%;
                border: 1px solid black;
            }
            .olControlZoomLine {
                bottom: 23px;
                display: block;
                font-size: small;
                left: 10px;
                position: absolute;
            }
            .olControlScaleLine {
                bottom: 15px;
                display: block;
                font-size: xx-small;
                left: 40px !important;
                position: absolute;
            }
            .olControlClickBar {
                top: 8px;
                right: 6px;
                border: 1px solid black;
                border-radius: 3px;
                background: white;
                padding-left: 4px;
                padding-right: 4px;
                font: 10px monospace;
                cursor: pointer;
            }
        </style>

        <script  type="text/javascript">
            OpenLayers.Util.extend( OpenLayers.INCHES_PER_UNIT, {
                "NM": OpenLayers.INCHES_PER_UNIT["nmi"],
                "cbl": OpenLayers.INCHES_PER_UNIT["nmi"]/10,
            });

    //        Proj4js.defs["EPSG:3857"]="+title=GoogleMercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";

    //        var mapProjection = "EPSG:3857";
            log('OpenLayers.VERSION_NUMBER',OpenLayers.VERSION_NUMBER);

            TilesetXYZ = OpenLayers.Class(OpenLayers.Layer.XYZ, {

                initialize: function(tilemap) {
                    var serverResolutions
                    if (tilemap.tilesets) {
                        serverResolutions = []
                        for (var i in tilemap.tilesets) {
                            var ts = tilemap.tilesets[i]
                            serverResolutions[i] = ts.units_per_pixel
                        }
                    }

                    var options = {
                        //~ sphericalMercator: true,
                        projection: tilemap.crs.properties.name,
                        wrapDateLine: true,
                        isBaseLayer: false,
                        transitionEffect: null,
                        displayOutsideMaxExtent: false,
                        maxExtent: new OpenLayers.Bounds(tilemap.tiles.max_extent),
                        tileOrigin: new OpenLayers.LonLat(tilemap.tiles.origin),
                        tileSize: new OpenLayers.Size(
                            tilemap.tiles.size[0],
                            tilemap.tiles.size[1]
                        ),
                        serverResolutions: serverResolutions,
                    }

                    OpenLayers.Layer.XYZ.prototype.initialize.call(
                        this,
                        tilemap.properties.title,
                        "z${z}/${y}/${x}." + tilemap.tiles.ext,
                        options
                    )
                },

                setMap: function(map) {
                    OpenLayers.Layer.XYZ.prototype.setMap.call(this, map)
                    //~ this.serverResolutions = this.resolutions
                },

                getServerResolution: function(resolution) {
                    resolution = resolution || this.map.getResolution();
                    if (! this.serverResolutions ||
                            OpenLayers.Util.indexOf(this.serverResolutions, resolution) !== -1)
                        return resolution

                    var serverResolution = null;
                    for (var i = this.serverResolutions.length - 1; i >= 0; i--) {
                        serverResolution = this.serverResolutions[i];
                        if (serverResolution >= resolution) {
                            break;
                        }
                    }
                    higherResolution = this.serverResolutions[i+1]
                    if (! higherResolution) { // map resolution is beyond highest server resolution
                        if (resolution / serverResolution < 0.9)
                            return resolution
                        else
                            return serverResolution
                    }
                    if (serverResolution == null ||
                            resolution - higherResolution < serverResolution - resolution) {

                        serverResolution = higherResolution
                    }
                    //~ if (serverResolution === null)
                        //~ throw 'no appropriate resolution in serverResolutions';

                    return serverResolution
                },

                transformDiv: function(scale) {

                    // scale the layer div

                    this.div.style.width = Math.round(100 * scale) + '%';
                    this.div.style.height = Math.round(100 * scale) + '%';

                    // and translate the layer div as necessary

                    var size = this.map.getSize();
                    var lcX = parseInt(this.map.layerContainerDiv.style.left, 10);
                    var lcY = parseInt(this.map.layerContainerDiv.style.top, 10);
                    var x = (lcX - (size.w / 2.0)) * (scale - 1);
                    var y = (lcY - (size.h / 2.0)) * (scale - 1);

                    this.div.style.left = Math.round(x) + '%';
                    this.div.style.top = Math.round(y) + '%';
                },

                getURL: function (bounds) {
                    var url = OpenLayers.Layer.XYZ.prototype.getURL.apply(this, arguments)
                    log('getURL', url)
                    return url
                },

                CLASS_NAME: "OpenLayers.Layer.TilesetXYZ"
            })

            OpenLayers.Control.ZoomLine = OpenLayers.Class(OpenLayers.Control, {
                autoActivate: true,

                activate: function () {
                    if (! OpenLayers.Control.prototype.activate.apply(this, arguments))
                        return false

                    //~ this.log("activate")
                    this.eventsMonitoring(true)

                    this.update()
                    return true
                },

                deactivate: function () {
                    if (!this.active)
                        return false

                    //~ this.log("DEactivate")
                    this.div.innerHTML = ''
                    this.eventsMonitoring(false)

                    return OpenLayers.Control.prototype.deactivate.apply(this, arguments)
                },

                eventsMonitoring: function (on_off) {
                    this.map.events[on_off ? 'on' : 'un'].call(
                        this.map.events,
                        {
                            'moveend': this.update,
                            scope: this,
                        }
                    )
                },

                update: function() {
                    this.div.innerHTML = 'z' + this.map.getZoom()
                },

                CLASS_NAME: "OpenLayers.Control.ZoomLine"
            })

            OpenLayers.Control.ClickBar = OpenLayers.Class(OpenLayers.Control, {

                clickBarDiv: null,
                divEvents: null,
                title : 'Click to set opacity of the overlay',

                /**
                 * Constructor: OpenLayers.Control.ClickBar
                 *
                 * Parameters:
                 * options - {Object}
                 */
                initialize: function(options) {
                    OpenLayers.Control.prototype.initialize.apply(this, arguments);
                },

                /**
                 * APIMethod: destroy
                 */
                destroy: function() {

                    this._removeClickBar();
                    OpenLayers.Control.prototype.destroy.apply(this, arguments);
                },

                /**
                 * Method: redraw
                 * clear the div and start over.
                 */
                redraw: function() {
                    if (this.div != null) {
                        this._removeClickBar();
                    }
                    this.draw();
                },

                /**
                * Method: draw
                *
                * Parameters:
                * px - {<OpenLayers.Pixel>}
                */
                draw: function(px) {
                    // initialize our internal div
                    OpenLayers.Control.prototype.draw.apply(this, arguments);

                    this._addClickBar();
                    return this.div;
                },

                /**
                * Method: _addClickBar
                *
                * Parameters:
                * location - {<OpenLayers.Pixel>} where ClickBar drawing is to start.
                */
                _addClickBar:function() {
                    var id = this.id + "_" + this.map.id;
                    var div = OpenLayers.Util.createDiv(
                                id,//'OpenLayers_Control_ClickBar' + this.map.id,
                                null,//location,
                                null,
                                null,
                                "relative");

                    this.clickBarDiv = div;
                    this.divEvents = new OpenLayers.Events(this, div, null, true,
                                                            {includeXY: true});
                    this.divEvents.on({
                        "click": this.click
                    });

                    this.div.appendChild(div);

                    this.ratioDisplay();
                    return this.div;
                },

                /**
                 * Method: _removeClickBar
                 */
                _removeClickBar: function() {
                    this.divEvents.un({
                        "click": this.click
                    });
                    this.divEvents.destroy();

                    this.div.removeChild(this.clickBarDiv);
                    this.clickBarDiv = null;
                },

                click: function (event) {
                    this.clickToRatio(event);
                },

                ratio: 0.5,

                clickMargin: 7,

                clickToRatio: function(event) {
                    var rect=this.clickBarDiv.getBoundingClientRect();
                    var w=rect.width-this.clickMargin*2;
                    var offx= (event.layerX !== undefined) ? event.layerX : event.offsetX;
                    var ratio=(offx-this.clickMargin)/w;
                    if (ratio < 0) ratio=0;
                    if (ratio > 1) ratio=1;
                    this.ratio=ratio;
                    this.ratioDisplay();
                    },

                reportRatio: null, // function(ratio){log(ratio)},

                ratioDisplay: function (){
                    var s = OpenLayers.Number.format(this.ratio,1);
                    this.clickBarDiv.innerHTML = '<- ' + s + ' ->'
                    this.reportRatio(this.ratio);
                    },

                CLASS_NAME: "OpenLayers.Control.ClickBar"
            });
        // OpenLayers.Control.ClickBar

        function error(msg) {
            alert(msg);
            throw new Error(msg);
        }

        function log(msg) {
            try { console.log.apply(console,arguments) }
            catch (e) {
                setTimeout(function() {
                    throw new Error(msg);
                }, 0);
            }
        }

        /*
           Provide the XMLHttpRequest constructor for Internet Explorer 5.x-6.x:
           Other browsers (including Internet Explorer 7.x-9.x) do not redefine
           XMLHttpRequest if it already exists.

           This example is based on findings at:
           http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
        */
        if (typeof XMLHttpRequest == "undefined")
          XMLHttpRequest = function () {
            try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
              catch (e) {}
            try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
              catch (e) {}
            try { return new ActiveXObject("Microsoft.XMLHTTP"); }
              catch (e) {}
            //Microsoft.XMLHTTP points to Msxml2.XMLHTTP and is redundant
            error("This browser does not support XMLHttpRequest.");
          };

        function read_text(url,mime) {
            var request = new XMLHttpRequest();
            request.open('GET', url, false);
            request.overrideMimeType(mime);
            /*
            request.onreadystatechange = function() {
                log('this.readyState',this.readyState);
                if(this.readyState == 4) {
                  alert("Loaded xml.\nresponseXml: " + xmlhttp.responseXML);
                    }
                }
              */
            try {
                request.send();
                if (request.status != 0) {
                    log('######################### request.status',request.status,request.responseText);
                }
            } catch (err) {
                var e = err;
                log('######################### e.code',e.code);
                if (/Chrom/.test(navigator.userAgent)) {
                    error('Loading error. Try to start Chrome with "--allow-file-access-from-files" switch')
                } else if (/Opera/.test(navigator.userAgent)) {
                    error('Loading error. Try to turn on "Allow File XMLHttpRequest" at the Opera configuration')
                }
                    throw e;
            }
            return request.responseText;
        }

        function read_tilemap() {
            var tilemap_txt=read_text("tilemap.json","application/json");
            if (tilemap_txt == null) {
                error('Cannot read tilemap.json');
                return null;
            };

            //log(tilemap_txt);
            var tilemap = JSON.parse(tilemap_txt);
            //log(tilemap);

            if (tilemap.type != 'TileMap') {
                error('tilemap.json: incorrect format');
                return null;
            };

            if (tilemap.crs.properties.name != 'EPSG:3857') {
                error('tilemap.json: unsupported CRS');
                return null;
            };

            return tilemap;
        }

        function initialize_openlayers() {
            var map = new OpenLayers.Map('map', {
//                  projection: new OpenLayers.Projection("EPSG:900913"), //mapProjection,
//                  displayProjection: new OpenLayers.Projection("EPSG:4326"),
                    units: "m",
                    maxResolution: 156543.0339,
                    maxExtent: new OpenLayers.Bounds(-20037508.342789, -20037508.342789, 20037508.342789, 20037508.342789),
                    controls: [
                        new OpenLayers.Control.Navigation(),
                        new OpenLayers.Control.PanZoomBar(),
                        //new OpenLayers.Control.MousePosition(),
                        new OpenLayers.Control.KeyboardDefaults(),
                        new OpenLayers.Control.LayerSwitcher({
                            'ascending':false
                        }),
                        new OpenLayers.Control.ScaleLine({
                            maxWidth: 50,
                            bottomOutUnits: 'NM',
                            bottomInUnits: 'cbl'
                        }),
                    ]
            });

            var osm = new OpenLayers.Layer.OSM(
                "Open Street Map",'http://tile.openstreetmap.org/${z}/${x}/${y}.png',
                {
                    displayOutsideMaxExtent: false,
                });

            var tilemap = read_tilemap();
            document.title = tilemap.properties.title;

            var tileset_overlay = new TilesetXYZ(tilemap)

            map.addLayers([osm, tileset_overlay]);
            map.zoomToExtent(new OpenLayers.Bounds(tilemap.bbox), true);

            map.addControl(
                new OpenLayers.Control.ClickBar({
                    ratio: 1,
                    reportRatio: function(ratio){
                        //log(ratio);
                        if (OpenLayers.Util.alphaHack() == false)
                            tileset_overlay.setOpacity(ratio);
                    },
                })
            );

            map.addControl(new OpenLayers.Control.ZoomLine())

            // Bing layers

            // API key for http://openlayers.org. Please get your own at
            // http://bingmapsportal.com/ and use that instead.
            var apiKey = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf";

            var road = new OpenLayers.Layer.Bing({
                name: "Bing Road",
                key: apiKey,
                type: "Road"
            });
            var hybrid = new OpenLayers.Layer.Bing({
                name: "Bing Hybrid",
                key: apiKey,
                type: "AerialWithLabels"
            });
            var aerial = new OpenLayers.Layer.Bing({
                name: "Bing Aerial",
                key: apiKey,
                type: "Aerial"
            });

            map.addLayers([road, hybrid, aerial]);

            // Google layers
            var gphy = new OpenLayers.Layer.Google(
                "Google Physical",
                {type: google.maps.MapTypeId.TERRAIN}
            );
            var gmap = new OpenLayers.Layer.Google(
                "Google Streets", // the default
                {numZoomLevels: 20}
            );
            var ghyb = new OpenLayers.Layer.Google(
                "Google Hybrid",
                {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20}
            );
            var gsat = new OpenLayers.Layer.Google(
                "Google Satellite",
                {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22}
            );

            map.addLayers([gphy, gmap, ghyb, gsat]);
        }
        </script>
    </head>

    <body onload="initialize_openlayers()">
        <div id='map'></div>
    </body>
</html>
